﻿#region File and License Information
/*
<File>
	<Copyright>Copyright © 2007, Daniel Vaughan. All rights reserved.</Copyright>
	<License see="prj:///Documentation/License.txt"/>
	<Owner Name="Daniel Vaughan" Email="dbvaughan@gmail.com"/>
	<CreationDate>2009-01-18 17:05:21Z</CreationDate>
	<LastSubmissionDate>$Date: $</LastSubmissionDate>
	<Version>$Revision: $</Version>
</File>
*/
#endregion

using System.Collections.Generic;

namespace DanielVaughan.AI.NeuralNetworking
{
	public partial class NeuralNetwork
	{
		/// <summary>
		/// Measures the accuracy of the neural network.
		/// </summary>
		/// <returns>A value between 0 and 1. The higher the value 
		/// the more accurate the neural network is deemed to be.</returns>
		public double MeasureAccuracy()
		{
			if (totalTrainingSet == null)
			{
				return 0;
			}

			var inputs = new List<double[]>();
			var outputs = new List<double[]>();
			foreach (var pair in totalTrainingSet.InputOutputDictionary)
			{
				inputs.Add(pair.Key.Data);
				outputs.Add(pair.Value.Data);
			}

			return MeasureAccuracy(inputs.ToArray(), outputs.ToArray());
		}

		/// <summary>
		/// Measures the accuracy of the neural network.
		/// </summary>
		/// <param name="input">The input set.</param>
		/// <param name="expectedOutput">The expected output set.</param>
		/// <returns>A value between 0 and 1. The higher the value 
		/// the more accurate the neural network is deemed to be.</returns>
		public double MeasureAccuracy(bool[][] input, bool[][] expectedOutput)
		{
			ArgumentValidator.AssertNotNull(input, "input");
			ArgumentValidator.AssertNotNull(expectedOutput, "expectedOutput");

			var inputDoubles = ConvertToDoubleArray(input);
			var expectedOutputDoubles = ConvertToDoubleArray(expectedOutput);
			return MeasureAccuracy(inputDoubles, expectedOutputDoubles);
		}

		/// <summary>
		/// Measures the accuracy of the neural network.
		/// </summary>
		/// <param name="input">The input set.</param>
		/// <param name="expectedOutput">The expected output set.</param>
		/// <returns>A value between 0 and 1. The higher the value 
		/// the more accurate the neural network is deemed to be.</returns>
		public double MeasureAccuracy(double[][] input, double[][] expectedOutput)
		{
			ArgumentValidator.AssertNotNull(input, "input");
			ArgumentValidator.AssertNotNull(expectedOutput, "expectedOutput");

			double accumulatedDifference = 0;
			int count = 0;
			for (int i = 0; i < input.Length; i++)
			{
				var inputRow = input[i];
				for (int j = 0; j < inputRow.Length; j++)
				{
					InputLayer[j].Output = inputRow[j];
				}

				Pulse();

				var outputRow = expectedOutput[i];
				for (int j = 0; j < outputRow.Length; j++)
				{
					double neuronOutput = OutputLayer[j].Output;
					double expectedOutputValue = outputRow[j];
					/* Calculate the difference. */
					double difference = neuronOutput > expectedOutputValue
						? neuronOutput - expectedOutputValue : expectedOutputValue - neuronOutput;
					accumulatedDifference += difference;
					count++;
				}
			}
			double result = count != 0 ? 1 - (accumulatedDifference / count) : 0;
			return result;
		}
	}
}
